//+------------------------------------------------------------------+
//|                                                       OpenCL.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| 用于操作OpenCL的类                                               |
//+------------------------------------------------------------------+
class COpenCL
{
protected:
   int               m_context;         // OpenCL上下文句柄
   int               m_program;         // OpenCL程序句柄
   //--- 内核相关
   string            m_kernel_names[];  // 内核名称数组
   int               m_kernels[];        // 内核句柄数组
   int               m_kernels_total;    // 内核总数
   //--- 缓冲区相关
   int               m_buffers[];       // 缓冲区句柄数组
   int               m_buffers_total;    // 缓冲区总数
   string            m_device_extensions; // 设备扩展信息
   bool              m_support_cl_khr_fp64; // 是否支持双精度浮点

public:
   //---
   //| @brief 构造函数
   //| @details 初始化OpenCL对象
   //---
   COpenCL(void);
   
   //---
   //| @brief 析构函数
   //| @details 清理OpenCL资源
   //---
   ~COpenCL(void);
   
   //---
   //| @brief 获取上下文句柄
   //| @return OpenCL上下文句柄
   //---
   int               GetContext(void) const { return(m_context); }
   
   //---
   //| @brief 获取程序句柄
   //| @return OpenCL程序句柄
   //---
   int               GetProgram(void) const { return(m_program); }
   
   //---
   //| @brief 获取指定内核句柄
   //| @param kernel_index 内核索引
   //| @return 内核句柄
   //---
   int               GetKernel(const int kernel_index) const;
   
   //---
   //| @brief 获取指定内核名称
   //| @param kernel_index 内核索引
   //| @return 内核名称
   //---
   string            GetKernelName(const int kernel_index) const;
   
   //---
   //| @brief 获取全局内存大小
   //| @param global_memory_size 返回的全局内存大小
   //| @return 操作是否成功
   //---
   bool              GetGlobalMemorySize(long &global_memory_size);
   
   //---
   //| @brief 获取本地内存大小
   //| @param local_memory_size 返回的本地内存大小
   //| @return 操作是否成功
   //---
   bool              GetLocalMemorySize(long &local_memory_size);
   
   //---
   //| @brief 获取最大工作组大小
   //| @param max_workgroup_size 返回的最大工作组大小
   //| @return 操作是否成功
   //---
   bool              GetMaxWorkgroupSize(long &max_workgroup_size);
   
   //---
   //| @brief 检查是否支持双精度浮点
   //| @return 是否支持双精度浮点
   //---
   bool              SupportDouble(void) const { return(m_support_cl_khr_fp64); }
   
   //---
   //| @brief 初始化OpenCL环境
   //| @param program OpenCL程序代码
   //| @param show_log 是否显示日志
   //| @return 初始化是否成功
   //---
   bool              Initialize(const string program, const bool show_log = true);
   
   //---
   //| @brief 关闭OpenCL环境
   //| @details 释放所有资源
   //---
   void              Shutdown(void);
   
   //---
   //| @brief 创建OpenCL上下文
   //| @param device 使用的设备
   //| @return 创建是否成功
   //---
   bool              ContextCreate(const int device = CL_USE_ANY);
   
   //---
   //| @brief 清理上下文资源
   //| @details 释放缓冲区、内核和程序
   //---
   void              ContextClean(void);
   
   //---
   //| @brief 创建OpenCL程序
   //| @param program OpenCL程序代码
   //| @param show_log 是否显示日志
   //| @return 创建是否成功
   //---
   bool              ProgramCreate(const string program, const bool show_log = true);
   
   //---
   //| @brief 删除OpenCL程序
   //| @details 释放程序资源
   //---
   void              ProgramDelete(void);
   
   //---
   //| @brief 设置缓冲区数量
   //| @param total_buffers 缓冲区总数
   //| @return 设置是否成功
   //---
   bool              SetBuffersCount(const int total_buffers);
   
   //---
   //| @brief 设置内核数量
   //| @param total_kernels 内核总数
   //| @return 设置是否成功
   //---
   bool              SetKernelsCount(const int total_kernels);
   
   //---
   //| @brief 创建内核
   //| @param kernel_index 内核索引
   //| @param kernel_name 内核名称
   //| @return 创建是否成功
   //---
   bool              KernelCreate(const int kernel_index, const string kernel_name);
   
   //---
   //| @brief 释放内核
   //| @param kernel_index 内核索引
   //| @return 释放是否成功
   //---
   bool              KernelFree(const int kernel_index);
   
   //---
   //| @brief 获取设备信息
   //| @param prop 属性标识符
   //| @return 设备信息值
   //---
   long              GetDeviceInfo(const int prop);
   
   //---
   //| @brief 获取设备整数属性
   //| @param prop 属性枚举
   //| @return 属性值
   //---
   long              GetDeviceInfoInteger(ENUM_OPENCL_PROPERTY_INTEGER prop);
   
   //---
   //| @brief 获取内核整数属性
   //| @param kernel_index 内核索引
   //| @param prop 属性枚举
   //| @return 属性值
   //---
   long              GetKernelInfoInteger(const int kernel_index, ENUM_OPENCL_PROPERTY_INTEGER prop);
   
   //---
   //| @brief 创建缓冲区
   //| @param buffer_index 缓冲区索引
   //| @param size_in_bytes 缓冲区大小(字节)
   //| @param flags 创建标志
   //| @return 创建是否成功
   //---
   bool              BufferCreate(const int buffer_index, const uint size_in_bytes, const uint flags);
   
   //---
   //| @brief 释放缓冲区
   //| @param buffer_index 缓冲区索引
   //| @return 释放是否成功
   //---
   bool              BufferFree(const int buffer_index);
   
   //---
   //| @brief 从数组创建缓冲区
   //| @param buffer_index 缓冲区索引
   //| @param data 数据数组
   //| @param data_array_offset 数据数组偏移
   //| @param data_array_count 数据数量
   //| @param flags 创建标志
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferFromArray(const int buffer_index, T &data[], const uint data_array_offset, const uint data_array_count, const uint flags);
   
   //---
   //| @brief 从矩阵创建缓冲区
   //| @param buffer_index 缓冲区索引
   //| @param data 数据矩阵
   //| @param flags 创建标志
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferFromMatrix(const int buffer_index, matrix<T> &data, const uint flags);
   
   //---
   //| @brief 从向量创建缓冲区
   //| @param buffer_index 缓冲区索引
   //| @param data 数据向量
   //| @param flags 创建标志
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferFromVector(const int buffer_index, vector<T> &data, const uint flags);
   
   //---
   //| @brief 从缓冲区读取到矩阵
   //| @param buffer_index 缓冲区索引
   //| @param data 目标矩阵
   //| @param rows 矩阵行数
   //| @param cols 矩阵列数
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferToMatrix(const int buffer_index, matrix<T> &data, const ulong rows = -1, const ulong cols = -1);
   
   //---
   //| @brief 从缓冲区读取到向量
   //| @param buffer_index 缓冲区索引
   //| @param data 目标向量
   //| @param size 向量大小
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferToVector(const int buffer_index, vector<T> &data, const ulong size = -1);
   
   //---
   //| @brief 从缓冲区读取数据
   //| @param buffer_index 缓冲区索引
   //| @param data 目标数组
   //| @param cl_buffer_offset 缓冲区偏移
   //| @param data_array_offset 数据数组偏移
   //| @param data_array_count 数据数量
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferRead(const int buffer_index, T &data[], const uint cl_buffer_offset, const uint data_array_offset, const uint data_array_count);
   
   //---
   //| @brief 写入数据到缓冲区
   //| @param buffer_index 缓冲区索引
   //| @param data 源数据数组
   //| @param cl_buffer_offset 缓冲区偏移
   //| @param data_array_offset 数据数组偏移
   //| @param data_array_count 数据数量
   //| @return 操作是否成功
   //---
   template<typename T>
   bool              BufferWrite(const int buffer_index, T &data[], const uint cl_buffer_offset, const uint data_array_offset, const uint data_array_count);
   
   //---
   //| @brief 设置内核参数
   //| @param kernel_index 内核索引
   //| @param arg_index 参数索引
   //| @param value 参数值
   //| @return 设置是否成功
   //---
   template<typename T>
   bool              SetArgument(const int kernel_index, const int arg_index, T value);
   
   //---
   //| @brief 设置内核缓冲区参数
   //| @param kernel_index 内核索引
   //| @param arg_index 参数索引
   //| @param buffer_index 缓冲区索引
   //| @return 设置是否成功
   //---
   bool              SetArgumentBuffer(const int kernel_index, const int arg_index, const int buffer_index);
   
   //---
   //| @brief 设置内核本地内存参数
   //| @param kernel_index 内核索引
   //| @param arg_index 参数索引
   //| @param local_memory_size 本地内存大小
   //| @return 设置是否成功
   //---
   bool              SetArgumentLocalMemory(const int kernel_index, const int arg_index, const int local_memory_size);
   
   //---
   //| @brief 执行内核
   //| @param kernel_index 内核索引
   //| @param work_dim 工作维度
   //| @param work_offset 工作偏移
   //| @param work_size 工作大小
   //| @return 执行是否成功
   //---
   bool              Execute(const int kernel_index, const int work_dim, const uint &work_offset[], const uint &work_size[]);
   
   //---
   //| @brief 执行内核(带本地工作组大小)
   //| @param kernel_index 内核索引
   //| @param work_dim 工作维度
   //| @param work_offset 工作偏移
   //| @param work_size 工作大小
   //| @param local_work_size 本地工作组大小
   //| @return 执行是否成功
   //---
   bool              Execute(const int kernel_index, const int work_dim, const uint &work_offset[], const uint &work_size[], const uint &local_work_size[]);
   
   //---
   //| @brief 获取内核执行状态
   //| @param kernel_index 内核索引
   //| @return 执行状态枚举
   //---
   ENUM_OPENCL_EXECUTION_STATUS ExecutionStatus(const int kernel_index);
};
//+------------------------------------------------------------------+